package com.andox.fn.inf.rpc.rest.parser;


import java.util.UUID;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.andox.fn.inf.rpc.rest.config.MethodConfig;


/**   
 * @ClassName:   ReferenceDefinitionParser   
 * @Description: TODO  
 * @author:      Andox
 * @date:        2019年7月29日 下午12:03:33   
 *     
 */
public class MethodDefinitionParser {
    private static final String ASYNC_ATTRIBUTE = "async";
    private static final String TIME_OUT_ATTRIBUTE = "timeout";
    private static final String ONEWAY_ATTRIBUTE = "oneway";
    private static final String EXCLUDE_ATTRIBUTE = "exclude";
    private static final String NAME_ATTRIBUTE = "name";
    
    public static void parse(Element element, ParserContext parserContext,
                                   BeanDefinitionBuilder builder) {
        NodeList nodeList = element.getChildNodes();
    	parseMethods(UUID.randomUUID().toString(), nodeList, builder, parserContext);
    }

    private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required){
    	BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); 
    	String name = element.getAttribute(NAME_ATTRIBUTE);
    	if (!StringUtils.hasText(name))
    		throw new IllegalArgumentException("<method name=\"\" /> name attribute lost.");
		builder.addPropertyValue(NAME_ATTRIBUTE, name);
    	
    	String timeout = element.getAttribute(TIME_OUT_ATTRIBUTE);
        if (StringUtils.hasText(timeout))
        	builder.addPropertyValue(TIME_OUT_ATTRIBUTE, timeout);
        
        String async = element.getAttribute(ASYNC_ATTRIBUTE);
        if (StringUtils.hasText(async))
        	builder.addPropertyValue(ASYNC_ATTRIBUTE, async);
        
        String oneway = element.getAttribute(ONEWAY_ATTRIBUTE);
        if (StringUtils.hasText(oneway))
        	builder.addPropertyValue(ONEWAY_ATTRIBUTE, oneway);
        
        String exclude = element.getAttribute(EXCLUDE_ATTRIBUTE);
        if (StringUtils.hasText(exclude))
        	builder.addPropertyValue(EXCLUDE_ATTRIBUTE, exclude);
        return builder.getBeanDefinition();
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static void parseMethods(String id, NodeList nodeList, BeanDefinitionBuilder beanDefinition,
                              ParserContext parserContext) {
        if (nodeList != null && nodeList.getLength() > 0) {
            ManagedList methods = null;
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if (node instanceof Element) {
                    Element element = (Element) node;
                    if ("method".equals(node.getNodeName()) || "method".equals(node.getLocalName())) {
                        String methodName = element.getAttribute("name");
                        if (methodName == null || methodName.length() == 0) {
                            throw new IllegalStateException("<dubbo:method> name attribute == null");
                        }
                        if (methods == null) {
                            methods = new ManagedList();
                        }
                        BeanDefinition methodBeanDefinition = parse(((Element) node),
                                parserContext, MethodConfig.class, false);
                        String name = id + "." + methodName;
                        BeanDefinitionHolder methodBeanDefinitionHolder = new BeanDefinitionHolder(
                                methodBeanDefinition, name);
                        methods.add(methodBeanDefinitionHolder);
                    }
                }
            }
            if (methods != null) {
                beanDefinition.addPropertyValue("methodConfigs", methods);
            }
        }
    }
}